package hero_summon

import (
	"go_server/game_server/api/service/bag"
	"go_server/game_server/api/service/hero_info"
	"go_server/game_server/dao/count_down_dao"
	"go_server/game_server/dao/daily_dao"
	"go_server/game_server/dataconfig/config_manager"
	"go_server/game_server/event_manager"
	"go_server/game_server/event_manager/event_data/event_impl"
	"go_server/game_server/protocol/pb"
	"go_server/game_server/util"
	"go_server/game_server/world_manager"
	"go_server/zinx/ziface"
	"go_server/zinx/zlog"
	"go_server/zinx/znet"
	"gorm.io/datatypes"
	"time"
)

type SummonHeroApi struct {
	znet.BaseRouter
}

// 英雄招募
func (*SummonHeroApi) Handle(request ziface.IRequest) {
	msg := &pb.SummonHeroC2S{}
	if !util.PBParseRet(request, msg) {
		return
	}

	conn := request.GetConnection()
	roleId := ServiceObj.GetRoleId(request)

	if msg.Num <= 0 {
		world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_PARAM_ERROR, nil)
		return
	}

	drawConfig := config_manager.GetStcTableHeroDraw_SheetDrawList()
	if len(drawConfig) <= 0 {
		world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_POOL_NOT_EXIST, nil)
		return
	}

	if msg.Num > drawConfig[msg.Type].DrawMax {
		world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_LIMIT_MAX, nil)
		return
	}

	drawItems := config_manager.GetStcTableHeroDraw_SheetDrawItemListByType(msg.Type)
	if len(drawItems) <= 0 {
		world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_POOL_PRIZE_NOT_EXIST, nil)
		return
	}

	var spendItemId = drawConfig[msg.Type].Consume[0]  // 单个英雄招募消耗道具id
	var spendItemNum = drawConfig[msg.Type].Consume[1] // 单个英雄招募消耗道具数量
	var DrawLimit = drawConfig[msg.Type].DrawLimit     // 每日抽取次数上限
	var drawNum = drawConfig[msg.Type].DrawNum         // 单抽抽取奖品数量

	// 判断抽奖道具是否足够
	if msg.IsFree <= 0 && !bag.CheckItemEnough(roleId, spendItemId, msg.Num*spendItemNum) {
		world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_SPEND_ITEM_ID_NOT_ENOUGH, nil)
		return
	}

	rateMap := make(map[int32]int32) // 概率权重列表
	for _, drawItem := range drawItems {
		rateMap[drawItem.Id] = drawItem.Weight
	}

	// 获取当日已使用的免费次数
	dateKey := time.Now().Format("20060102")
	row := daily_dao.GetDailyByDateKey(dateKey, roleId, []string{"hero_summon_use_free_time", "hero_summon_times"})

	heroSummonUseFreeTime := make(map[int32]int32)
	heroSummonTimes := make(map[int32]int32)

	if row != nil {
		if row.HeroSummonUseFreeTime.Data() != nil {
			heroSummonUseFreeTime = row.HeroSummonUseFreeTime.Data()
		}

		if row.HeroSummonTimes.Data() != nil {
			heroSummonTimes = row.HeroSummonTimes.Data()
		}
	}

	// 不是免费抽取
	if msg.IsFree <= 0 {
		hadSummonTimes, ok := heroSummonTimes[msg.Type] // 今日已抽取次数
		if ok {
			if hadSummonTimes >= DrawLimit { // 超过当日累计抽取次数上限
				world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_TIMES_LIMIT, nil)
				return
			}

			heroSummonTimes[msg.Type] = hadSummonTimes + msg.Num
		} else {
			heroSummonTimes[msg.Type] = msg.Num
		}
	}

	// 获取上次使用免费抽次数时间
	fields1 := []string{"hero_summon_last_time"}
	row1 := count_down_dao.GetCountDownByRoleId(roleId, fields1)

	heroSummonLastTime := make(map[int32]int64)
	if row1 != nil && row1.HeroSummonLastTime.Data() != nil {
		heroSummonLastTime = row1.HeroSummonLastTime.Data()
	}

	_, isNotFirst := heroSummonLastTime[msg.Type] // 是否是当前奖池首抽, 默认为 false,是首抽

	// 免费抽取
	if msg.IsFree > 0 {
		hadUseTimes, exist := heroSummonUseFreeTime[msg.Type]
		if exist && hadUseTimes >= drawConfig[msg.Type].FreeNum {
			world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_FREE_COUNT_OVERFLOW, nil)
			return
		}

		if isNotFirst && (time.Now().UnixMilli()-heroSummonLastTime[msg.Type]) < int64(drawConfig[msg.Type].Time*1000) {
			world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_HERO_SUMMON_FREE_TIMES_CANT_REFRESH, nil)
			return
		}

		if exist {
			heroSummonUseFreeTime[msg.Type] += 1 // 今日已使用免费次数 +1
		} else {
			heroSummonUseFreeTime[msg.Type] = 1
		}

		heroSummonLastTime[msg.Type] = time.Now().UnixMilli() // 更新最近一次免费招募时间

		msg.Num = 1 // 免费抽取只能是单抽
	}

	summonHeroStateList := make(map[int32]*pb.SummonHeroStateInfo) // 抽取的奖励列表

	for _, typeValue := range SummonTypes {
		summonHeroStateInfo := new(pb.SummonHeroStateInfo)
		var remainFreeTimes = drawConfig[typeValue].FreeNum // 剩余免费次数
		var refreshTime int64 = 0                           // 下次使用免费抽奖时间,新人为 0

		hadUseTimes, exist := heroSummonUseFreeTime[typeValue]
		if exist {
			if hadUseTimes >= drawConfig[typeValue].FreeNum {
				remainFreeTimes = 0
			} else {
				remainFreeTimes = drawConfig[typeValue].FreeNum - hadUseTimes
			}
		}

		lastTime, exist1 := heroSummonLastTime[typeValue]
		if exist1 {
			// 获取次日凌晨零点的时间戳，单位毫秒
			timeStr := time.Now().Format("2006-01-02")
			t2, _ := time.ParseInLocation("2006-01-02", timeStr, time.Local)
			nextDayTime := t2.AddDate(0, 0, 1).UnixMilli()

			// 下次刷新时间超过次日0点
			if (lastTime + int64(drawConfig[typeValue].Time*1000)) >= nextDayTime {
				refreshTime = lastTime + int64(drawConfig[typeValue].Time*1000)
			} else {
				// 未超过次日0点，则判断当日免费次数是否使用完
				if remainFreeTimes <= 0 { // 今日剩余免费次数为0
					refreshTime = nextDayTime // 下次刷新时间为次日0点
				} else {
					refreshTime = lastTime + int64(drawConfig[typeValue].Time*1000)
				}
			}
		}

		summonHeroStateInfo.RefreshTime = refreshTime
		summonHeroStateInfo.RemainFreeTimes = remainFreeTimes
		summonHeroStateList[typeValue] = summonHeroStateInfo
	}

	sheetItemMap := config_manager.GetTableItemSheetItemMap()

	var heroItemIds []int32                   // 抽取到的英雄列表
	goodsList := make(map[int32]*pb.GoodInfo) // 抽取的奖励列表
	indexMap := make(map[int32][]int32)       // [返回下标:[奖励id,是否是英雄本体,英雄本体heroId,是否需要转化为英雄碎片]]
	totalNum := msg.Num * drawNum

	for i := int32(0); i < totalNum; i++ {
		var goodId int32

		// 普通奖池、新人首抽
		if !isNotFirst && msg.Type == HERO_SUMMON_ORDINARY_PRIZE_POOL && i == 0 {
			goodId = drawConfig[msg.Type].Firstdraw[0] // 新人首抽默认赠送物品
		} else {
			// 随机英雄
			goodId, _ = util.GetRandWeight(rateMap)
		}

		goodInfo := new(pb.GoodInfo)
		goodInfo.GoodId = goodId
		goodInfo.State = 0 // 默认为转化为英雄碎片

		goodsList[i] = goodInfo

		// 判断是否是英雄本体
		itemId := drawItems[goodId].Itemid
		itemType := sheetItemMap[itemId].Type
		itemPar := sheetItemMap[itemId].Par

		indexMap[i] = []int32{goodId, 0, 0, 0}

		if itemType == 23 { // 是英雄本体
			if itemPar[0] != 2 { // 英雄参数配置错误
				world_manager.WorldMgrObj.SendClientErrMsg(roleId, request, pb.ErrorCodeManager_PARAM_ERROR, nil)
				return
			}
			heroId := itemPar[1]

			heroItemIds = append(heroItemIds, heroId)
			indexMap[i] = []int32{goodId, 1, heroId, 0}
		}
	}

	if len(heroItemIds) > 0 {
		zlog.Infof("招募返回 ,heroItemIds=%v", heroItemIds)

		// 批量获取当前抽到的英雄的拥有状态
		heroStates, _ := hero_info.Hero_info_serviceObj.ContainsHeroCfgIds(roleId, heroItemIds)

		zlog.Infof("招募返回 ,heroStates=%v", heroStates)

		for i, state := range indexMap {
			if state[1] > 0 { // 对应的下标奖品是英雄本体
				heroInfo, exist := heroStates[state[2]] // 判断当前英雄是否拥有
				if !exist || !heroInfo {                // 英雄不存在
					heroStates[state[2]] = true // 改变当前英雄状态为 已拥有
				} else {
					goodsList[i].State = 1 // 英雄已拥有,需要转化成英雄碎片
					indexMap[i][3] = 1
				}
			}
		}
	}

	res := &pb.SummonHeroS2C{
		SummonHeroStateList: summonHeroStateList,
		GoodsList:           goodsList,
	}

	zlog.Infof("招募返回 ,indexMap=%v", indexMap)

	// 优先返回下行
	conn.SendBuffPBMsg(uint32(pb.ProtocolManager_SummonHero), res)

	if msg.IsFree <= 0 { // 非免费抽奖
		bag.SubItemSingle(roleId, spendItemId, msg.Num*spendItemNum) // 扣除招募道具

		dailyObj := daily_dao.Daily{
			DateKey:         dateKey,
			RoleId:          roleId,
			HeroSummonTimes: datatypes.NewJSONType(heroSummonTimes),
		}
		daily_dao.UpdateDailyByDateKey(&dailyObj, []string{"hero_summon_times"}) // 更新每日累计抽取次数
	} else { // 免费抽奖
		dailyObj := daily_dao.Daily{
			DateKey:               dateKey,
			RoleId:                roleId,
			HeroSummonUseFreeTime: datatypes.NewJSONType(heroSummonUseFreeTime),
		}
		daily_dao.UpdateDailyByDateKey(&dailyObj, []string{"hero_summon_use_free_time"}) // 更新每日使用免费次数,累计抽取次数

		countDown := count_down_dao.CountDown{
			RoleId:             roleId,
			HeroSummonLastTime: datatypes.NewJSONType(heroSummonLastTime), // 更新最新使用免费抽奖时间
		}
		count_down_dao.UpdateCountDown(&countDown, fields1)
	}

	// 发送招募奖励
	if len(indexMap) > 0 {
		prizeMap := make(map[int32]int32)
		heroIds := make([]int32, 0) // 需要发送的英雄本体列表

		for _, goodInfo := range indexMap {
			if goodInfo[1] > 0 { // 抽到英雄本体
				if goodInfo[3] <= 0 {
					heroIds = append(heroIds, goodInfo[2])
				} else { // 需要转化为英雄碎片
					cfgHero, _ := config_manager.GetStcTableHero_SheetHeroConfig(goodInfo[2])

					// 添加英雄本体转化为的碎片奖励
					_, ok := prizeMap[cfgHero.Unlockitemid]
					if !ok {
						prizeMap[cfgHero.Unlockitemid] = cfgHero.UnlockNum
					} else {
						prizeMap[cfgHero.Unlockitemid] += cfgHero.UnlockNum
					}
				}
			} else {
				goodConfig, _ := drawItems[goodInfo[0]] // 获取当前物品奖励配置

				_, ok := prizeMap[goodConfig.Itemid]
				if !ok {
					prizeMap[goodConfig.Itemid] = goodConfig.Num
				} else {
					prizeMap[goodConfig.Itemid] += goodConfig.Num
				}
			}
		}

		if len(prizeMap) > 0 {
			zlog.Infof("发送奖励 ,prizeMap=%v", prizeMap)

			bag.AddItemBatch(roleId, prizeMap) // 发送奖励
		}

		if len(heroIds) > 0 {
			zlog.Infof("发送英雄 ,heroIds=%v", heroIds)

			hero_info.Hero_info_serviceObj.S2C_AddHero(conn, roleId, heroIds)
		}

		// 英雄招募事件
		event_manager.EventManagerObj.FireEventData(event_impl.NewSummonHeroEvent(conn, map[string]int32{
			"id":    0,
			"value": msg.Num, // 次数
		}))
	}
}
